#ifndef __IOC_PLUGIN_MGR_H
#define __IOC_PLUGIN_MGR_H

#include <iostream>
#include <functional>
#include <map>
#include <memory>
#include <string>

struct Plugin
{
    virtual void act() {}
    virtual ~Plugin() {}
};

class PluginMgr
{
public:
    static PluginMgr* Instance();
public:
    PluginMgr() {}
    ~PluginMgr() {}

    Plugin* Resolve(std::string);
    std::shared_ptr<Plugin> ResolveShared(std::string);

    template<class T>
    inline void Register(const char *name)
    {
        std::string key(name);

        if (plugins_.find(key) != plugins_.end()) {
            std::string err = key + " has already exists.";
            throw std::invalid_argument(err.c_str());
        }

        std::function<Plugin *()> creator = []{ return new T(); };
        plugins_.emplace(key, creator);
    }

private:
    PluginMgr(const PluginMgr &) = delete;
    PluginMgr &operator=(const PluginMgr &) = delete;

private:
    std::map<std::string, std::function<Plugin* ()>> plugins_;
};

#endif
